import { watch, onMounted, onBeforeUnmount } from "vue"
import { type Options } from './type';
import Select from './select';
import { deepCopy } from "./util"

export default class extends Select {
  constructor(options: Options) {
    super(options);

    const restEdit = () => this.restEdit()

    onMounted(() => {
      document.body.addEventListener('mousedown', restEdit);
    })
    onBeforeUnmount(() => {
      document.body.removeEventListener('mousedown', restEdit);
    })
    
  };

  currentTd: HTMLElement | null = null;
  input: HTMLElement | null = null;
  oldValue: any;

  isEditer(rowindex: number, colindex: number) {
    return (
      !this.checkHasReadonly(this.selectAreasData.value.records) && 
      !this.checkHasDisable(this.selectAreasData.value.records) && 
      this.editState.editX === colindex && 
      this.editState.editY === rowindex
    );
  }

  async clickEditHandel(rowindex: number, colindex: number) {

    if (this.props.customEditer?.disabledSelectCell) return;

    // 在自由选择时，不进行任何操作
    if (event?.ctrlKey || event?.metaKey) return

    if ( this.editState.editX === colindex && this.editState.editY === rowindex ) {
      return;
    }

    this.editState.editX = colindex;
    this.editState.editY = rowindex;

    if (this.checkHasReadonly(this.selectAreasData.value.records)) return;
    if (this.checkHasDisable(this.selectAreasData.value.records)) return;

    if (this.props.customEditer?.onEditBefore){
      await this.props.customEditer?.onEditBefore?.(this.selectAreasData.value, this);
    }

    let autoFocusTimer: any = this.findInput(rowindex, colindex)
    this.editState.status = 'ready';

    const keyboardInput = (e: any) => {
      // console.log(e)
      if (
        e.metaKey ||
        e.ctrlKey ||
        [
          91, // command
          17, // ctrl
          37,
          38,
          39,
          40, // 方向键
          46,
          8, // delete
          16, // 向上翻页
          13, // 回车enter
          123, // F12
          27, // esc
          9,
          18, // alt
        ].includes(e.keyCode)
      )
        return true;

      if (this.editState.status === 'ready') {
        const dataIndex = this.columns.value[this.editState.editX].dataIndex
        this.setValueByModel(dataIndex, this.dataSource.value[this.editState.editY], undefined)
      }

      document.removeEventListener('keydown', keyboardInput);
      this.editState.status = 'doing';
      this.input?.focus?.();
    };

    document.removeEventListener('keydown', keyboardInput);
    document.addEventListener('keydown', keyboardInput);

    const stopWatcher = watch(
      () => [this.selectedState.startX, this.selectedState.startY],
      () => {
        document.removeEventListener('keydown', keyboardInput);
        this.input?.blur?.();
        clearTimeout(autoFocusTimer)
        autoFocusTimer = null;
        this.input = null
        stopWatcher();
      },
      {
        deep: true,
      },
    );
  }

  async dblclickEditHandel(rowindex: number, colindex: number) {
    if (this.props.customEditer?.disabledSelectCell) return;
    if (!this.selectAreasData.value.records?.length) return;
    if (this.checkHasReadonly(this.selectAreasData.value.records)) return;
    if (this.checkHasDisable(this.selectAreasData.value.records)) return;

    if (this.props.customEditer?.onEditBefore){
      await this.props.customEditer?.onEditBefore?.(this.selectAreasData.value, this);
    }

    this.findInput(rowindex, colindex);
    this.editState.status = 'doing';
    setTimeout(() => {
      this.input?.focus?.();
    }, 0)
  }

  private findInput(rowindex: number, colindex: number){
  
    let td: HTMLElement | undefined | null;
    if(event?.type === 'keydown') {
      td = this.getCellElement({rowindex: rowindex, colindex: colindex})
    } else {
      td = event?.currentTarget || (event?.target as any);
      while (td?.tagName !== 'TD') {
        td = td?.parentNode as HTMLElement;
      }
    }
    this.currentTd = td as HTMLElement;

    const nextDraw = () => {
      this.getOldValue(rowindex, colindex)

      const input = td?.querySelector?.('input') || this.table.value?.querySelector('table+textarea');
      if(input) {
        if(!this.isInputNumber(input)) input?.focus?.();
        if(input === this.input) return;
        this.input = input;

        const cancelDefaultUpDown = () => {
          // 上下键
          if ([38, 40].includes(event.keyCode)) {
            event?.stopPropagation();
            event?.preventDefault();

            document.dispatchEvent(new KeyboardEvent('keydown', event));
            return false;
          }
        }
        this.input.addEventListener('keydown', cancelDefaultUpDown)

      };

      // console.log(input)
      // select edit event
      if(
        !input || 
        input.dataset.inputtype === 'select' || 
        input.classList.contains('ant-select-selection-search-input') || 
        input.classList.contains('ant-input-number-input')
      ){
        this.onFocus(rowindex, colindex)
        const stopwatch = watch(this.selectedState, () => {
          const oldValue = this.oldValue;
          const column = this.columns.value[colindex];
          const record = this.dataSource.value[rowindex];

          if(this.getValueByModel(column.dataIndex, record) !== oldValue) {
            this.onChange(rowindex, colindex)
          }
          this.onBlur(rowindex, colindex)

          stopwatch()
        }, {
          deep: true
        })
      } else if(input){
        this.margeInputEvents(rowindex, colindex)
      }
    }

    // Promise.resolve().then(nextDraw)
    return setTimeout(nextDraw, 0);
  }

  private isInputNumber(input: HTMLElement){
    return input.classList.contains('ant-input-number-input') || input.getAttribute('type') === 'number'
  }

  private margeInputEvents(rowindex: number, colindex: number){
    const focusHandel = () => this.onFocus(rowindex, colindex);
    const changeHandel = () => this.onChange(rowindex, colindex);
    const blurHandel = () => this.onBlur(rowindex, colindex);
    const keydownHandel = () => this.onKeydown(rowindex, colindex);

    const removeEvents = () => {
      this.input?.removeEventListener('keydown', keydownHandel)
      this.input?.removeEventListener('change', changeHandel)
      this.input?.removeEventListener('blur', blurHandel)
    }

    removeEvents()
    this.input?.addEventListener('keydown', keydownHandel)
    this.input?.addEventListener('change', changeHandel)
    this.input?.addEventListener('blur', blurHandel)

    const stopWatcherEditStatus = watch(() => this.editState.status, (status) => {
      if(status === 'doing') focusHandel()
    })
    const stopWatcher = watch(
      () => [this.selectedState.startX, this.selectedState.startY],
      () => {
        removeEvents()
        stopWatcher()
        stopWatcherEditStatus()
      },
      {
        deep: true,
      },
    );

    
  }

  private getOldValue(rowindex: number, colindex: number){
    const record = this.dataSource.value[rowindex]
    const column = this.columns.value[colindex]
    this.oldValue = deepCopy(this.getValueByModel(column.dataIndex, record))
  }

  private restEdit() {
    let node: any = event?.target;
    while (node && node !== document.body) {
      // 防止下拉，proup等误触发
      if (
        node === this.currentTd ||
        Array.from(node?.classList).includes('ant-dropdown')
      )
        return false;
      node = node.parentElement;
    }
    this.editState.editX = this.editState.editY = undefined;
    this.editState.status = undefined;
  }

  private onChange(rowindex: number, colindex: number){
    if(this.props.openUndo) this.addHistoryRecord();

    this.tryValidateCell?.(rowindex, colindex, 'change');

    if(typeof this.props.customEditer?.onChange !== 'function') return

    const column = this.columns.value[colindex];
    const record = this.dataSource.value[rowindex];

    this.props.customEditer?.onChange({
      oldValue: this.oldValue,
      newValue: this.getValueByModel(column.dataIndex, record),
      column: this.columns.value[colindex], 
      record: this.dataSource.value[rowindex]
    })
  }

  private onFocus(rowindex: number, colindex: number){
    if(typeof this.props.customEditer?.onFocus !== 'function') return

    const column = this.columns.value[colindex];
    const record = this.dataSource.value[rowindex];

    this.props.customEditer?.onFocus({
      value: this.getValueByModel(column.dataIndex, record),
      column: this.columns.value[colindex], 
      record: this.dataSource.value[rowindex]
    })
  }

  private onBlur(rowindex: number, colindex: number){

    this.tryValidateCell?.(rowindex, colindex, 'blur');

    if(typeof this.props.customEditer?.onBlur !== 'function') return 

    const column = this.columns.value[colindex];
    const record = this.dataSource.value[rowindex];

    this.props.customEditer?.onBlur({
      oldValue: this.oldValue,
      newValue: this.getValueByModel(column.dataIndex, record),
      column: this.columns.value[colindex], 
      record: this.dataSource.value[rowindex]
    })
  }

  private onKeydown(rowindex: number, colindex: number) {
    if (this.isInputNumber(this.input) && this.editState.status === 'doing' && (event?.key === 'ArrowUp' || event?.key === 'ArrowDown')) {
      event?.stopPropagation();
      event?.preventDefault();
      this.triggerKeyEvent('keydown', event?.keyCode)
      return false
    }
  }

  private triggerKeyEvent(type: 'keydown' | 'keyup', keyCode: 40 | 38) {
    const event = new KeyboardEvent(type, {
        keyCode: keyCode,
        which: keyCode,
        key: String.fromCharCode(keyCode),
    });
    document.dispatchEvent(event);
  }
}
